<?php
/**
*
* example目录下为简单的支付样例，仅能用于搭建快速体验微信支付使用
* 样例的作用仅限于指导如何使用sdk，在安全上面仅做了简单处理， 复制使用样例代码时请慎重
* 请勿直接直接使用样例对外提供服务
* 官方文档：https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
**/

require_once "./plugins/WxPay/lib/WxPay.Api.php";
require_once "./plugins/WxPay/WxPay.Config.php";
require_once './plugins/WxPay/lib/WxPay.Notify.php';
require_once "./plugins/WxPay/lib/phpqrcode.php";
require_once "./plugins/WxPay/lib/WxPay.NativePay.php";
require_once "./plugins/WxPay/WxPay.JsApiPay.php";

const PAY_LOG_PATH = './log/wx/';

//模式二
/**
 * 流程：
 * 1、调用统一下单，取得code_url，生成二维码
 * 2、用户扫描二维码，进行支付
 * 3、支付完成之后，微信服务器会通知支付成功
 * 4、在支付成功通知中需要查单确认是否真正支付成功（见：notify.php）
 */
class WxPayCall
{

    // 订单失效时间
    const ORDER_EXPIRE_TIME = 600;

    // native 发送下单请求
    public static function SendPayRequest($product_desc, $attach, $order_no, $total_fee, $product_id) {
        $input = new WxPayUnifiedOrder();

        $input->SetBody($product_desc); // 商品简单描述  浏览器打开的网站主页title名 -商品概述 eg:日新活动中心-活动购票
        $input->SetAttach($attach); // 附加数据  附加数据，在查询API和支付通知中原样返回，可作为自定义参数使用
        $input->SetOut_trade_no($order_no); // 商户订单号  商户系统内部订单号，要求32个字符内，只能是数字、大小写字母_-|* 且在同一个商户号下唯一
        $input->SetTotal_fee($total_fee);  // 标价金额  订单总金额，单位为分
//        $input->SetTime_start(date("YmdHis"));
//        $input->SetTime_expire(date("YmdHis", time() + self::ORDER_EXPIRE_TIME));
        //$input->SetGoods_tag("test");
//        $input->SetNotify_url($callback_url);  // 通知地址  异步接收微信支付结果通知的回调地址，通知url必须为外网可访问的url，不能携带参数
        $input->SetTrade_type("NATIVE"); // 交易类型  JSAPI 公众号支付  NATIVE 扫码支付  APP APP支付
        $input->SetProduct_id($product_id);  // 商品ID  trade_type=NATIVE时（即扫码支付），此参数必传。此参数为二维码中包含的商品ID，商户自行定义

        $result     = self::GetPayUrl($input);
        $code_url   = $result["code_url"];

        return QRcode::png($code_url, false, 'H', 6);
    }

    // h5发送下单请求
    public static function sendH5PayRequest($product_desc, $attach, $order_no, $total_fee, $redirect_url)
    {
        $input = new WxPayUnifiedOrder();
        $input->SetBody($product_desc); // 商品简单描述  浏览器打开的网站主页title名 -商品概述 eg:日新活动中心-活动购票
        $input->SetAttach($attach); // 附加数据  附加数据，在查询API和支付通知中原样返回，可作为自定义参数使用
        $input->SetOut_trade_no($order_no); // 商户订单号  商户系统内部订单号，要求32个字符内，只能是数字、大小写字母_-|* 且在同一个商户号下唯一
        $input->SetTotal_fee($total_fee);  // 标价金额  订单总金额，单位为分
        $input->SetNotify_url(get_current_http_type() . C('DOMAIN_NAME') . "/index.php/Wx/WxPay/notify"); //支付完成之后，微信服务器通知的回调地址
        $input->SetTrade_type("MWEB"); //特别注意这里的类型
        $input->SetScene_info('{"h5_info": {"type":"Wap","wap_url": ' . C('DOMAIN_NAME') . ',"wap_name": ' . $product_desc . '}}');

        $url    = new NativePay();
        $result = $url->GetH5PayUrl($input);
        $url    = $result["mweb_url"].'&redirect_url='.urlencode($redirect_url); //后面加的&redirect_url=http%3A%2F%2Fxxx.com是支付成功后的跳转页面,$url为生成的支付链接url
        return $url;
    }

    // 微信内直接调起支付
    public static function getJsapiPayParameters($product_desc, $attach, $order_no, $total_fee, $product_id, $open_id)
    {
        $tools = new JsApiPay();
        $input = new WxPayUnifiedOrder();
        $input->SetBody($product_desc);
        $input->SetAttach($attach);
        $input->SetOut_trade_no($order_no);
        $input->SetTotal_fee($total_fee);
        $input->SetNotify_url(get_current_http_type() . C('DOMAIN_NAME') . "/index.php/Wx/WxPay/notify"); //支付完成之后，微信服务器通知的回调地址
        $input->SetTrade_type("JSAPI");
        $input->SetProduct_id($product_id);
        $input->SetOpenid($open_id);

        $config = new WxPayConfig();
        $order = WxPayApi::unifiedOrder($config, $input);
        $jsApiParameters = $tools->GetJsApiParameters($order);
        return $jsApiParameters;
    }

    // 微信小程序内直接调起支付
    public static function getMiniPayParameters($product_desc, $attach, $order_no, $total_fee, $product_id, $open_id)
    {
        $tools = new JsApiPay();
        $input = new WxPayUnifiedOrder();
        $input->SetBody($product_desc);
        $input->SetAttach($attach);
        $input->SetOut_trade_no($order_no);
        $input->SetTotal_fee($total_fee);
        $input->SetNotify_url(get_current_http_type() . C('DOMAIN_NAME') . "/index.php/Wx/WxPay/notify"); //支付完成之后，微信服务器通知的回调地址
        $input->SetTrade_type("JSAPI");
        $input->SetProduct_id($product_id);
        $input->SetOpenid($open_id);

        $config = new WxPayConfig();
        $config->setPayType('mini');
        $order = WxPayApi::unifiedOrder($config, $input);
        $jsApiParameters = $tools->GetJsApiParameters($order);
        return $jsApiParameters;
    }

    // 微信付款到用户零钱
    public static function refundOrder($trade_order_id, $amount, $desc, $open_id)
    {
        $input = new WxPayUnifiedOrder();
        $input->SetPartner_trade_no($trade_order_id);
        $input->SetOpenid($open_id);
        $input->SetAmount($amount);
        $input->SetDesc($desc);
        $input->SetCheck_name('NO_CHECK');
        $config = new WxPayConfig();
        $result = WxPayApi::refundOrder($config, $input);
        if ($result['status'] != 1) {
            $msg = $trade_order_id . ' refund failed  -- reason : ' . $result['err_code_des'];
            writeFile($msg, PAY_LOG_PATH);
        }
        return $result;
    }

    /**
     *
     * 生成直接支付url，支付url有效期为2小时,模式二
     * @param UnifiedOrderInput $input
     */
    public static function GetPayUrl($input)
    {
        if($input->GetTrade_type() == "NATIVE")
        {
            try{
                $config = new WxPayConfig();
                $result = WxPayApi::unifiedOrder($config, $input);
                return $result;
            } catch(Exception $e) {
                writeFile(json_encode($e), PAY_LOG_PATH);
            }
        }
        return false;
    }
}


// 回调
class PayNotifyCallBack extends WxPayNotify
{

    //查询订单
    public function Queryorder($transaction_id)
    {
        $input = new WxPayOrderQuery();
        $input->SetTransaction_id($transaction_id);

        $config = new WxPayConfig();
        $result = WxPayApi::orderQuery($config, $input);
//        Log::DEBUG("query:" . json_encode($result));
        if(array_key_exists("return_code", $result)
            && array_key_exists("result_code", $result)
            && $result["return_code"] == "SUCCESS"
            && $result["result_code"] == "SUCCESS")
        {
            return true;
        }
        return false;
    }


    // NATIVE 支付方式回调（申请支付二维码时，填写的回调地址）
    //重写回调处理函数
    /**
     * @param WxPayNotifyResults $data 回调解释出的参数
     * @param WxPayConfigInterface $config
     * @param string $msg 如果回调处理失败，可以将错误信息输出到该方法
     * @return true回调出来完成不需要继续回调，false回调处理未完成需要继续回调
     */
    public function NotifyProcess($objData, $config, &$msg)
    {
        $data = $objData->GetValues();

        //TODO 1、进行参数校验
        if(!array_key_exists("return_code", $data) || (array_key_exists("return_code", $data) && $data['return_code'] != "SUCCESS")) {
            //TODO失败,不是支付成功的通知
            //如果有需要可以做失败时候的一些清理处理，并且做一些监控
            $msg = "参数异常";
            return false;
        }
        if(!array_key_exists("transaction_id", $data)){
            $msg = "输入参数不正确";
            return false;
        }

        //TODO 2、进行签名验证
        try {
            $checkResult = $objData->CheckSign($config);
            if($checkResult == false){
                //签名错误
                $msg = "签名错误";
                return false;
            }
        } catch(Exception $e) {
            writeFile($e, PAY_LOG_PATH);
        }


        //查询订单，判断订单真实性
//        if(!$this->Queryorder($data["transaction_id"])){
//            $msg = "订单查询失败";
//            return false;
//        }

        //TODO 3、处理业务逻辑

        if($data['result_code'] != 'SUCCESS') {
            // 付款失败
            $error_data = array(
                'info'          => 'pay_fail',
                'err_code'      => $data['err_code'],
                'err_code_des'  => $data['err_code_des'],
                'attach'        => $data['attach'],
            );
            writeFile($error_data, PAY_LOG_PATH);
        }

        $pay_type   = $data['attach'];
        $info       = array();
        $info['transaction_id'] = $data['transaction_id'];
        $info['total_fee']      = $data['total_fee'];
        $info['trade_order_id'] = $data['out_trade_no'];
        $info['pay_type']       = $pay_type;

        \Order\Model\OrderModel::PayCallBack($info);

        return true;
    }

    public static function notify()
    {
        $config = new WxPayConfig();
        $notify = new PayNotifyCallBack();
        $notify->Handle($config, false);
    }
}